package my.suveng.oauth2.service.user.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.caller.CallerUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.log.Log;
import cn.hutool.log.LogFactory;
import com.alibaba.fastjson.JSON;
import com.querydsl.core.QueryResults;
import com.querydsl.jpa.impl.JPAQueryFactory;
import my.suveng.model.common.interfaces.response.IMessage;
import my.suveng.model.common.response.Message;
import my.suveng.model.common.response.element.ElementPage;
import my.suveng.model.common.response.element.PageQuery;
import my.suveng.oauth2.model.dto.PermissionAddDto;
import my.suveng.oauth2.model.dto.PermissionDeleteDto;
import my.suveng.oauth2.model.dto.PermissionEditDto;
import my.suveng.oauth2.model.dto.PermissionSearch;
import my.suveng.oauth2.model.enums.StatusEnums;
import my.suveng.oauth2.service.auth.impl.AuthServiceImpl;
import my.suveng.oauth2.service.db.mysql.dao.jpa.SysPermissionRepository;
import my.suveng.oauth2.service.db.mysql.dao.jpa.SysPermissionRoleRepository;
import my.suveng.oauth2.service.db.mysql.model.entity.*;
import my.suveng.oauth2.service.user.IPermissionService;
import my.suveng.util.log.PlusLogFactoryHutool;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import javax.persistence.criteria.Predicate;
import java.util.ArrayList;
import java.util.List;

/**
 *
 * @author suwenguang
 **/
@Service
public class PermissionServiceImpl implements IPermissionService {

    // hutool日志
    private static final Log log = LogFactory.setCurrentLogFactory(new PlusLogFactoryHutool())
            .getLog(CallerUtil.getCaller().getName());

    @Autowired
    private SysPermissionRepository sysPermissionRepository;
    @Autowired
    private JPAQueryFactory jpaQueryFactory;
    @Autowired
    private AuthServiceImpl authService;
    @Autowired
    private SysPermissionRoleRepository sysPermissionRoleRepository;

    /**
     * 多条件搜索 权限列表
     *
     * @author suwenguang
     */
    public IMessage<ElementPage<List<SysPermission>>> list(PageQuery<PermissionSearch> query) {
        // 使用mybatis
        Specification<SysPermission> specification = buildSpecification(query);
        Sort.Order order = query.order();

        Page<SysPermission> list;
        Specification<SysPermission> where = Specification.where(specification);

        if (ObjectUtil.isEmpty(order)) {
            list = sysPermissionRepository.findAll(where,
                    PageRequest.of(query.getCurrentPage() - 1, query.getPageSize()));
        } else {
            Sort sort = Sort.by(order);
            list = sysPermissionRepository.findAll(where,
                    PageRequest.of(query.getCurrentPage() - 1, query.getPageSize(), sort));
        }

        return ElementPage.build(list.getTotalElements(), list.getContent());
    }

    /**
     * 构造多条件搜索 根据参数动态替换
     *
     * @author suwenguang
     */
    private static Specification<SysPermission> buildSpecification(PageQuery<PermissionSearch> query) {
        PermissionSearch search = query.getSearch();
        if (ObjectUtil.isEmpty(search)) {
            return null;
        }

        return (Specification<SysPermission>) (root, criteriaQuery, criteriaBuilder) -> {

            List<Predicate> list = new ArrayList<>();

            if (ObjectUtil.isNotEmpty(search.getId())) {
                list.add(criteriaBuilder.equal(root.get("id").as(Long.class), search.getId()));
            }

            // name模糊查询
            if (StrUtil.isNotBlank(search.getName())) {
                list.add(criteriaBuilder.like(root.get("name").as(String.class), "%" + search.getName() + "%"));
            }

            if (ObjectUtil.isNotEmpty(search.getCreator())) {
                list.add(criteriaBuilder.equal(root.get("creator").as(Long.class), search.getCreator()));
            }

            if (ObjectUtil.isNotEmpty(search.getUpdator())) {
                list.add(criteriaBuilder.equal(root.get("updator").as(Long.class), search.getUpdator()));
            }

            if (ObjectUtil.isNotEmpty(search.getStatus())) {
                list.add(criteriaBuilder.equal(root.get("status").as(Integer.class), search.getStatus()));
            }

            // 时间
            if (StrUtil.isNotBlank(search.getCreateTimeStart())) {
                list.add(criteriaBuilder.greaterThanOrEqualTo(root.get("createTime").as(String.class),
                        search.getCreateTimeStart()));

            }
            if (StrUtil.isNotBlank(search.getCreateTimeEnd())) {
                list.add(criteriaBuilder.lessThan(root.get("createTime").as(String.class), search.getCreateTimeEnd()));
            }

            // 时间
            if (StrUtil.isNotBlank(search.getModifyTimeStart())) {
                list.add(criteriaBuilder.greaterThanOrEqualTo(root.get("modifyTime").as(String.class),
                        search.getModifyTimeStart()));
            }
            if (StrUtil.isNotBlank(search.getModifyTimeEnd())) {
                list.add(criteriaBuilder.lessThan(root.get("modifyTime").as(String.class), search.getModifyTimeEnd()));
            }

            Predicate[] p = new Predicate[list.size()];
            return criteriaBuilder.and(list.toArray(p));
        };
    }

    /**
     * 增加权限
     *
     * @author suwenguang
     */
    public IMessage<SysPermission> add(PermissionAddDto permissionAddDto) {
        String name = permissionAddDto.getPermissionName();
        QSysPermission sysPermission = QSysPermission.sysPermission;
        // 限制校验
        SysPermission check = jpaQueryFactory.selectFrom(sysPermission).where(sysPermission.name.eq(name)).fetchOne();
        if (ObjectUtil.isNotEmpty(check)) {
            throw new RuntimeException("权限已存在");
        }

        SysPermission permission = new SysPermission();
        permission.setName(name);
        // 获取登录用户信息
        SysUser user = authService.getSysUser();
        if (ObjectUtil.isEmpty(user)) {
            throw new RuntimeException("用户不存在");
        }
        permission.setCreator(user.getId());
        permission.setStatus(StatusEnums.UP.getKey());

        SysPermission save = sysPermissionRepository.save(permission);
        if (ObjectUtil.isEmpty(save.getId())) {
            log.error("保存权限失败,{}", JSON.toJSONString(save));
            return Message.error("保存权限失败");
        }

        return Message.successWithData(save);
    }

    /**
     * 修改权限
     *
     * @author suwenguang
     */
    public IMessage<SysPermission> edit(PermissionEditDto permissionEditDto) {
        // 限制校验
        QSysPermission qSysPermission = QSysPermission.sysPermission;
        SysPermission sysPermission = jpaQueryFactory.selectFrom(qSysPermission)
                .where(qSysPermission.name.eq(permissionEditDto.getName())).fetchOne();
        if (ObjectUtil.isNotEmpty(sysPermission)) {
            log.info("已存在相同名字的权限,record={}", JSON.toJSONString(sysPermission));
            return Message.error("已存在相同名字的权限");
        }

        // 属性转化
        SysPermission entity = jpaQueryFactory.selectFrom(qSysPermission)
                .where(qSysPermission.id.eq(permissionEditDto.getId())).fetchOne();
        if (ObjectUtil.isEmpty(entity)) {
            log.info("记录不存在,record={}", JSON.toJSONString(entity));
            return Message.error("记录不存在");
        }

        // 更新人
        SysUser sysUser = authService.getSysUser();
        if (ObjectUtil.isEmpty(sysUser)) {
            log.info("用户信息为空");
            return Message.error("用户信息为空");
        }
        entity.setName(permissionEditDto.getName());
        entity.setUpdator(sysUser.getId());

        SysPermission save = sysPermissionRepository.save(entity);
        if (!save.getName().equals(permissionEditDto.getName())) {
            log.info("修改失败,target={},source={},id={}", save.getName(), permissionEditDto.getName(),
                    permissionEditDto.getId());
            return Message.error("修改失败");
        }

        return Message.successWithData(save);
    }

    /**
     * 根据id删除权限以及其关联关系
     *
     * @author suwenguang
     *
     * @param permissionDeleteDto
     *            封装
     */
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRES_NEW)
    public IMessage<Object> deleteById(PermissionDeleteDto permissionDeleteDto) {
        // 物理删除

        // 删除权限-角色的关联关系
        QSysPermissionRole qSysPermissionRole = QSysPermissionRole.sysPermissionRole;
        QueryResults<SysPermissionRole> sysPermissionRoleQueryResults = jpaQueryFactory.selectFrom(qSysPermissionRole)
                .where(qSysPermissionRole.permissionId.eq(permissionDeleteDto.getId())).fetchResults();
        List<SysPermissionRole> sysPermissionRoleList = sysPermissionRoleQueryResults.getResults();
        if (CollUtil.isNotEmpty(sysPermissionRoleList)) {
            sysPermissionRoleList.parallelStream().forEach(result -> {
                sysPermissionRoleRepository.deleteById(result.getId());
            });
        }

        // 删除权限表记录
        sysPermissionRepository.deleteById(permissionDeleteDto.getId());

        return Message.success();
    }
}
